package com.example.netty.nio;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {
    public static void main(String[] args) throws IOException {
        /**
         * bio中使用serverSocket进行端口号设置和监听，真正的通讯需要用socket
         * nio中使用serverSocketChannel进行端口号的设置和监听，真正通讯需要用socketChannel（都是多了个channel的后缀）
         */

        //创建一个serverSocketChannel，并设置端口号,非阻塞模式
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));
        serverSocketChannel.configureBlocking(false);
        //创建一个selector
        Selector selector = Selector.open();
        //将serverSocketChannel绑定到selector,第二个参数需要设置关心的时间
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //进行循环监听
        while (true) {
            //调用selector的监听方法,这里使用超时中断
            if (selector.select(10000) == 0) {
                System.out.println("服务器等待了十秒，没有事件");
                continue;
            }
            System.out.println("\n监听到事件，正在获取selectionKey," +
                    "serverSocketChannel关注的key数量（未处理的，已处理的会被移除）："
                    +selector.selectedKeys().stream().count() +
                    " 所有的key数量："+selector.keys().stream().count());

            //select调用返回大于零，说明有连接事件，直接获取所有注册到selector的channel关注的selectionKey集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            //遍历所有的key
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                //从iterrantor获取key
                SelectionKey key = iterator.next();
                //判断不同的时间类型
                if (key.isAcceptable()) {
                    System.out.println("收到连接事件，正在生成socketChannel通讯通道。。。");
                    //连接事件 OP_ACCEPT,生成一个socketChannel进行通讯
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    //先设置非阻塞模式,再将socketChannel注册到selector,还需要设置关注事件 、 buffer
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                    System.out.println("客户端连接成功,已成功将socketChannel注册到selector,socketChannel:"+socketChannel.hashCode());
                }
                if (key.isReadable()) {
                    System.out.println("收到读取事件，正在通过selectionKey获取对应的socketChannel通讯通道。。。");
                    //读取事件 OP_READ
                    //通过key获取channel
                    SocketChannel channel = (SocketChannel)key.channel();
                    //通过key获取buffer
                    ByteBuffer buffer = (ByteBuffer)key.attachment();
                    //读取操作
                    channel.read(buffer);
                    System.out.println("一则来自客户端的消息："+new String(buffer.array()));
                }

                //手动删除key，防止重复操作（必须有调用了next，才可以是用remove，不然会快速失败）
                iterator.remove();
            }

        }
    }
}








